package com.peoit.honeycomb.shiro;

import com.peoit.honeycomb.application.UserApplication;
import com.peoit.honeycomb.domain.User;
import com.peoit.honeycomb.domain.security.Permission;
import com.peoit.honeycomb.domain.security.Person;
import com.peoit.honeycomb.domain.security.Role;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.apache.commons.lang3.StringUtils;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;

/**
 *权限鉴定
 * Created by zhouqiu on 2015/10/12.
 */
public class MySecurityRealm extends AuthorizingRealm {

    private static final Logger LOGGER = LoggerFactory.getLogger(MySecurityRealm.class);

    private UserApplication userApplication;

    /**
     * 为当前登录的Subject授予角色和权限
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
      //获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next()
     String currentUsername = (String)super.getAvailablePrincipal(principals);
       List<String> roleList = new ArrayList<String>();
      List<String> permissionList = new ArrayList<String>();
      //从数据库中获取当前登录用户的详细信息
        Person personBy = userApplication.getPersonBy(currentUsername);
        if(null != personBy){
          //实体类personBy中包含有用户角色的实体类信息
          if(null!=personBy.getRoles() && personBy.getRoles().size()>0){
              //获取当前登录用户的角色
              for(Role role : personBy.getRoles()){
                  roleList.add(role.getName());
                  //实体类Role中包含有角色权限的实体类信息
                  if(null!=role.getPermissions() && role.getPermissions().size()>0){
                      //获取权限
                      for(Permission pmss : role.getPermissions()){
                          if(!StringUtils.isEmpty(pmss.getName())){
                              permissionList.add(pmss.getName());
                          }
                      }
                  }
              }
          }
      }else{
          throw new AuthorizationException();
      }
      //为当前用户设置角色和权限
      SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
      simpleAuthorInfo.addRoles(roleList);
      simpleAuthorInfo.addStringPermissions(permissionList);
        return simpleAuthorInfo;

        /*SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
        User user = userApplication.getUserBy(currentUsername);
        //实际中可能会像上面注释的那样从数据库取得
        if(null!=user){
            //添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色
            simpleAuthorInfo.addRole("admin");
            //添加权限
            simpleAuthorInfo.addStringPermission("user");
            return simpleAuthorInfo;
        }
        //若该方法什么都不做直接返回null的话,就会导致任何用户访问/admin/listUser.jsp时都会自动跳转到unauthorizedUrl指定的地址
        //详见applicationContext.xml中的<bean id="shiroFilter">的配置
        return null;*/
    }

    /**
     * 验证当前登录的Subject
     * @param authcToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        //获取基于用户名和密码的令牌
        //实际上这个authcToken是从LoginController里面currentUser.login(token)传过来的
        //两个token的引用都是一样的,本例中是org.apache.shiro.authc.UsernamePasswordToken@33799a1e
        UsernamePasswordToken token = (UsernamePasswordToken)authcToken;
        String username = token.getUsername();
//        System.out.println("验证当前Subject时获取到token为" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));
        System.out.println("验证当前Subject时获取到token为" +token.getUsername());
      Person personBy = userApplication.getPersonBy(username); 
        if(null != personBy){
          AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(personBy.getName(), personBy.getPassword(), this.getName());
          this.setSession("accessToken", personBy.getName());
          this.setSession("accessTokenId", personBy.getId());
          return authcInfo;
      }else{
          return null;
      }
    }

    /**
     * 将一些数据放到ShiroSession中,以便于其它地方使用
     */
    private void setSession(Object key, Object value){
        Subject currentUser = SecurityUtils.getSubject();
        if(null != currentUser){
            Session session = currentUser.getSession();
            if(null != session){
                session.setAttribute(key, value);
            }
        }
    }

    public UserApplication getUserApplication() {
        return userApplication;
    }

    public void setUserApplication(UserApplication userApplication) {
        this.userApplication = userApplication;
    }
}
